package com.tansun.ruledata.data.service.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.drools.mvel.MVELConstraint;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.tansun.rule.config.AppConfiguration;
import com.tansun.rule.exception.RuleConsequenceExceptionHandler;
import com.tansun.rule.exception.RuleInvokeException;
import com.tansun.rule.listener.ExecuterProcessEventListener;
import com.tansun.rule.pojo.EnterPoint;
import com.tansun.rule.utils.DroolsRuleLog;
import com.tansun.rule.utils.MClass;
import com.tansun.rule.utils.RuleHelper;
import com.tansun.ruledata.data.service.RuleDataEngineService;
import com.tansun.ruledata.data.service.RuleResourceLoadService;
import com.tansun.ruledata.sessionpool.SessionDataPool;


@Service
public class RuleDataEngineServiceImpl implements RuleDataEngineService {

	@Autowired
	private  RuleResourceLoadService  ruleResourceLoadService;
	@Override
	public Map<String, Object> invokeRule(String ruleObjectName, String invokePoint, String invokeType, Map<String, Object> maps,
			DroolsRuleLog droolsRuleLog) throws Exception {
		//drools 异常捕获类 静态属性初始化
		RuleConsequenceExceptionHandler.droolsRuleLog = droolsRuleLog;
		String poolKey = ruleObjectName+"_"+invokePoint;
		
		Map<String,EnterPoint> eMap = AppConfiguration.ruleEnterMap.get(ruleObjectName);
		SessionDataPool sessionPool =null;
		EnterPoint enterPoint = null;
		//第一次调用要初始化session池
		if("job".equals(invokeType)){
			sessionPool = AppConfiguration.AppRuleProjDataPoolsForJob.get(poolKey);
		}else {
			sessionPool = AppConfiguration.AppRuleProjDataPools.get(poolKey);
		}
		Map<String, MClass> metaMap = AppConfiguration.RuleProjMetaMap.get(ruleObjectName);
		Map<String,String> drlMap  = AppConfiguration.ruleRefMap.get(poolKey);
		String  funDrl = AppConfiguration.funcMap.get(ruleObjectName);
		Map<String,String> pmmlMap = AppConfiguration.PmmlMap.get(ruleObjectName);
		
		//判断数据是否完备
		Boolean isPerfect = AppConfiguration.DataPerfect.get(poolKey);
		if(isPerfect== null || isPerfect == false) {
			if (eMap == null || eMap.isEmpty()){
				ruleResourceLoadService.loadEnterPoint(ruleObjectName,invokePoint);
				eMap =  AppConfiguration.ruleEnterMap.get(ruleObjectName);
				if (eMap == null || eMap.isEmpty()){
					throw new RuleInvokeException("项目不存在！");
				}
			}
			enterPoint = eMap.get(invokePoint);
			if(enterPoint==null){
				ruleResourceLoadService.loadEnterPoint(ruleObjectName,invokePoint);
				enterPoint =eMap.get(invokePoint);
			}
			if (enterPoint == null){
				throw new RuleInvokeException("服务入口不存在！");	
			}
			if (!"on".equals(enterPoint.getControl())){
				throw new RuleInvokeException("服务入口被禁止！");
			}
			//调用规则的过程 部署过程同时进行 调用等待
			//第一次调用要初始化session池
			if("job".equals(invokeType)){
				if(AppConfiguration.AppRuleProjDataPoolsForJob.get(poolKey)==null){
					this.ruleResourceLoadService.loadDeployedRuleFlow(ruleObjectName, invokePoint);
				}
				sessionPool = AppConfiguration.AppRuleProjDataPoolsForJob.get(poolKey);
			}else {
				if(AppConfiguration.AppRuleProjDataPools.get(poolKey) == null ){
					this.ruleResourceLoadService.loadEnterPointDeployResource(ruleObjectName, invokePoint);
				}
				sessionPool = AppConfiguration.AppRuleProjDataPools.get(poolKey);
			}
			
			if (metaMap == null || metaMap.isEmpty()){
				this.ruleResourceLoadService.loadProjectDataMapping(ruleObjectName);
				metaMap = AppConfiguration.RuleProjMetaMap.get(ruleObjectName);
			}
			if (drlMap ==null) {
				this.ruleResourceLoadService.loadProjectRefeDrl(ruleObjectName,invokePoint);
				drlMap  = AppConfiguration.ruleRefMap.get(ruleObjectName+"_"+invokePoint);
			}
			if (funDrl ==null) {
				this.ruleResourceLoadService.loadRuleFunctionDrl(ruleObjectName);
				funDrl = AppConfiguration.funcMap.get(ruleObjectName);
			}
			if(pmmlMap==null) {
		        ruleResourceLoadService.loadProjectPmml(ruleObjectName);
		        ruleResourceLoadService.loadProjectPmmlRefData(ruleObjectName);
			}
		}
		
		KieSession ksession = null;
		try {
			ksession = sessionPool.borrowKieSession();
		} catch (Exception e1) {
			e1.printStackTrace();
			throw  new RuleInvokeException(e1.getMessage());
		}

		RuleHelper ruleHelper = new RuleHelper(metaMap,maps,drlMap);
		ruleHelper.setProjectCode(ruleObjectName);
		ruleHelper.setFuncDrl(funDrl);
		if(ksession.getGlobal("ruleHelper")==null){
			ksession.setGlobal("ruleHelper", ruleHelper);
		}
		droolsRuleLog.setRuleHelper(ruleHelper);
		droolsRuleLog.setDataMap(maps);
		ksession.setGlobal("droolsRuleLog", null);
		ksession.setGlobal("droolsRuleLog", droolsRuleLog);
		ksession.setGlobal("metaMap", null);
		ksession.setGlobal("metaMap", metaMap);
		ksession.setGlobal("dataMap", null);
		ksession.setGlobal("dataMap", maps);
		ksession.insert(maps);
//		System.out.println("规则调用时间1:"+(System.currentTimeMillis()-start));
//		start = System.currentTimeMillis();
		try{
			//按照规则id调规则
			String ruleflowId = eMap.get(invokePoint).getRuleflowId();
			droolsRuleLog.setRuleFlowId(ruleflowId);
			droolsRuleLog.setVersion(eMap.get(invokePoint).getVersion());
			ExecuterProcessEventListener listener = new ExecuterProcessEventListener();
			ksession.addEventListener(listener);	
			ksession.startProcess(ruleflowId);		
			ksession.fireAllRules();
		}catch (Exception e){
			droolsRuleLog.addExceptionLogs(e);
			throw e;
		}
		ksession.setGlobal("droolsRuleLog", null);
		ksession.delete(ksession.getFactHandle(maps));	//清空对象
		ksession.dispose();
		sessionPool.returnKieSession(ksession);			//返回池对象
//		System.out.println("规则调用时间2:"+(System.currentTimeMillis()-start));
		if(isPerfect== null || isPerfect == false) {
			AppConfiguration.DataPerfect.put(poolKey,true);
		}
		return maps;
	}

	public Map<String, Object> invokeRule_citic(String ruleObjectName, String invokePoint, Map<String, Object> maps,DroolsRuleLog droolsRuleLog) throws Exception {
		//drools 异常捕获类 静态属性初始化
		RuleConsequenceExceptionHandler.droolsRuleLog = droolsRuleLog;
		Map<String,EnterPoint>  eMap =  AppConfiguration.ruleEnterMap.get(ruleObjectName);
		EnterPoint enterPoint =eMap.get(invokePoint);
		if (!"on".equals(enterPoint.getControl())){
			throw new RuleInvokeException("服务入口被禁止！");
		}
		String poolKey = ruleObjectName+"_"+invokePoint;
		SessionDataPool sessionPool = AppConfiguration.AppRuleProjDataPools.get(poolKey);
		KieSession ksession = null;
		try {
			ksession = sessionPool.borrowKieSession();
		} catch (Exception e1) {
			e1.printStackTrace();
			throw  new RuleInvokeException(e1.getMessage());
		}
		String  currDateTime = AppConfiguration.dateTimeMap.get(ruleObjectName+"_"+invokePoint) ;
		Map<String, MClass> metaMap = AppConfiguration.RuleProjMetaMap.get(ruleObjectName+"_"+currDateTime);
		Set<String> set =metaMap.keySet();
		if (maps == null){
			maps = new  HashMap<>();
		}
		Object  obj = null;
		for (String key :set){
			obj = maps.get(key);
			if (obj == null){
				maps.put(key, new HashMap<>());
			}
		}
//		RuleHelper ruleHelper = new RuleHelper(metaMap);
		RuleHelper ruleHelper = new RuleHelper(metaMap,maps,AppConfiguration.ruleRefMap.get(ruleObjectName+"_"+currDateTime));
	
		ruleHelper.setCurrDateTime(currDateTime);
		ruleHelper.setProjectCode(ruleObjectName);
		ruleHelper.setFuncDrl(AppConfiguration.funcMap.get(ruleObjectName+"_"+currDateTime));
		if(ksession.getGlobal("ruleHelper")==null){
			ksession.setGlobal("ruleHelper", ruleHelper);
		}
		droolsRuleLog.setRuleHelper(ruleHelper);
		droolsRuleLog.setDataMap(maps);
		ksession.setGlobal("droolsRuleLog", null);
		ksession.setGlobal("droolsRuleLog", droolsRuleLog);
		ksession.setGlobal("metaMap", null);
		ksession.setGlobal("metaMap", metaMap);
		ksession.setGlobal("dataMap", null);
		ksession.setGlobal("dataMap", maps);
		
		ksession.insert(maps);
		try{
			//按照规则id调规则
			String ruleflowId = eMap.get(invokePoint).getRuleflowId();
			droolsRuleLog.setRuleFlowId(ruleflowId);
			ExecuterProcessEventListener listener = new ExecuterProcessEventListener();
			ksession.addEventListener(listener);
			ksession.startProcess(ruleflowId);
			ksession.fireAllRules();
		}catch (Exception e){
			droolsRuleLog.addExceptionLogs(e);
			throw e;
		}finally {
			ksession.setGlobal("droolsRuleLog", null);
			ksession.delete(ksession.getFactHandle(maps));	//清空对象
			ksession.dispose();
			sessionPool.returnKieSession(ksession);			//返回池对象
		}
		return maps;
	}


	public RuleResourceLoadService getRuleResourceLoadService() {
		return ruleResourceLoadService;
	}



	public void setRuleResourceLoadService(RuleResourceLoadService ruleResourceLoadService) {
		this.ruleResourceLoadService = ruleResourceLoadService;
	}
	
	

}
